package com.hairline.hairlinemarket.shiro;

import com.hairline.hairlinemarket.bean.*;
import com.hairline.hairlinemarket.mapper.MarketAdminMapper;
import com.hairline.hairlinemarket.mapper.MarketPermissionMapper;
import com.hairline.hairlinemarket.mapper.MarketUserMapper;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 我们提供的Realm需要实现这个接口 → 这个接口提供的方法 → 获得认证信息和获得权限（授权）信息
 * → 谁封装了Realm ？  SecurityManager
 * 里面的方法是获得认证信息 → 谁要获得这个信息 → 认证器做认证 → realm作为认证器的成员变量
 * 里面的方法是获得授权信息 → 谁要获得这个信息 → 授权器做鉴权 → realm做授权器的成员变量
 *
 * @author stone
 * @date 2023/04/21 11:15
 */
@Component
public class WdRealm extends AuthorizingRealm {
    @Autowired
    MarketAdminMapper adminMapper;
    @Autowired
    MarketUserMapper marketUserMapper;

    @Autowired
    MarketPermissionMapper permissionMapper;

    // subject.login(usernamepasswordtoken) → 认证器执行认证过程需要获得认证信息 → 和数据库的信息有关系
    // 获得认证信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        WdToken token = (WdToken) authenticationToken;
        String username = token.getUsername();
        String tokenType = token.getType();
        if (tokenType.equals(WdToken.ADMIN_TYPE)) {
            // admin用户
            // 根据用户名查询admin记录
            MarketAdminExample example = new MarketAdminExample();
            example.createCriteria().andUsernameEqualTo(username);
            List<MarketAdmin> marketAdmins = adminMapper.selectByExample(example);
            if (marketAdmins != null && marketAdmins.size() > 0) {
                MarketAdmin admin = marketAdmins.get(0);
                // 数据库里的密码
                String credential = admin.getPassword();
                // 第一个参数就是通过Subject维护的Principal → 后续可以在任意位置通过subject.getPrincipal()来获得这个实例
                SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(admin, credential, getName());
                return authenticationInfo; // 不需要你自己做比对，authenticator会做比对 usernamepasswordtoken和credentials
            }
        } else if (tokenType.equals(WdToken.WX_TYPE)) {
            //wx用户
            MarketUserExample example = new MarketUserExample();
            example.createCriteria().andUsernameEqualTo(username);
            List<MarketUser> marketUsers = marketUserMapper.selectByExample(example);
            if(marketUsers!=null&&marketUsers.size()>0){
                MarketUser marketUser = marketUsers.get(0);
                String credential = marketUser.getPassword();
                SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(marketUser, credential, getName());
                return authenticationInfo;
            }
        }
        return null;
    }

    // 获得授权信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 授权是在认证的基础上进行的 → 当我们去获得授权信息的时候，说明已经认证成功了 → subject已经维护了Principal信息
        MarketAdmin principal = (MarketAdmin) principalCollection.getPrimaryPrincipal();
        Integer[] roleIds = principal.getRoleIds();
        MarketPermissionExample example = new MarketPermissionExample();
        example.createCriteria().andRoleIdIn(Arrays.asList(roleIds));
        List<MarketPermission> marketPermissions = permissionMapper.selectByExample(example);
        List<String> permissions = marketPermissions.stream().map(perm -> {
            return perm.getPermission();
        }).collect(Collectors.toList());
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addStringPermissions(permissions);
        return authorizationInfo;
    }

}
